﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using Wf5.Engine.Common;
using Wf5.Engine.Utility;

using FCDB.Entity;
using FCDB.Repository;

namespace Wf5.Engine.Business
{
    internal class ProcessInstanceManager
    {
        private WfProcessInstanceRepository _processInstanceRepository;
        private WfProcessInstanceRepository ProcessInstanceRepository
        {
            get
            {
                if (_processInstanceRepository == null)
                    _processInstanceRepository = new WfProcessInstanceRepository();
                return _processInstanceRepository;
            }
        }


        #region ProcessInstanceManager 基本数据操作
        /// <summary>
        /// 根据GUID获取流程实例数据
        /// </summary>
        /// <param name="processInstanceID"></param>
        /// <returns></returns>
        internal WfProcessInstance GetById(long processInstanceID)
        {
            return ProcessInstanceRepository.Get<WfProcessInstance>(processInstanceID);
        }

        /// <summary>
        /// 根据流程完成状态获取流程实例数据
        /// </summary>
        /// <param name="appName"></param>
        /// <param name="appInstanceID"></param>
        /// <param name="processGUID"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        internal IEnumerable<WfProcessInstance> GetProcessInstance(string appName,
            long appInstanceID,
            Guid processGUID)
        {
//            var whereSql = @"WHERE AppInstanceID=@appInstanceID 
//                                AND ProcessGUID=@processGUID 
//                                AND RecordStatusInvalid = 0
//                            ORDER BY CreatedDateTime DESC";

            return ProcessInstanceRepository.GetProcessInstance(appName,appInstanceID,processGUID);
        }

        internal WfProcessInstance GetProcessInstanceLatest(string appName,
            long appInstanceID,
            Guid processGUID)
        {
            WfProcessInstance entity = null;
            var processInstanceList = GetProcessInstance(appName, appInstanceID, processGUID).ToList();
            if (processInstanceList != null && processInstanceList.Count > 0)
            {
                entity = processInstanceList[0];
            }
            return entity;
        }


        /// <summary>
        /// 流程数据插入
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="wfLinqDataContext"></param>
        /// <returns></returns>
        internal void Insert(WfProcessInstance entity)
        {
            
            ProcessInstanceRepository.Add(entity  ); 
            Debug.WriteLine(string.Format("process instance inserted, Guid:{0}, time:{1}", entity.ID.ToString(), System.DateTime.Now.ToString()));
        }

        /// <summary>
        /// 流程实例更新
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="wfLinqDataContext"></param>
        internal void Update(WfProcessInstance entity )
        {
            ProcessInstanceRepository.Update(entity);
        }

        /// <summary>
        /// 根据流程定义，创建新的流程实例
        /// </summary>
        /// <param name="processID">流程定义ID</param>
        /// <returns>流程实例的ID</returns>
        internal WfProcessInstance CreateNewProcessInstanceObject(string appName, 
            long appInstanceID,
            WfProcess processEntity,
            Guid userID, 
            string userName)
        {
            WfProcessInstance entity = new WfProcessInstance();
            entity.ID = appInstanceID; 
            entity.ProcessGUID = processEntity.ProcessGUID;
            entity.ProcessName = processEntity.ProcessName;
            entity.AppName = appName;
            entity.AppInstanceID = appInstanceID;
            entity.ProcessState = (int)ProcessStateEnum.Running;
            entity.CreatedByUserID = userID;
            entity.CreatedByUserName = userName;
            entity.CreatedDateTime = System.DateTime.Now;
            entity.LastUpdatedByUserID = userID;
            entity.LastUpdatedByUserName = userName;
            entity.LastUpdatedDateTime = System.DateTime.Now;
           
            return entity;
        }
        #endregion

        #region 流程业务规则处理
        /// <summary>
        /// 流程完成，设置流程的状态为完成
        /// </summary>
        /// <returns>是否成功</returns>
        internal void Complete(long processInstanceID, 
            WfLogonUser currentUser)
        {
            var bEntity = GetById(processInstanceID);
            var processState = (ProcessStateEnum)Enum.Parse(typeof(ProcessStateEnum), bEntity.ProcessState.ToString());
            if ((processState | ProcessStateEnum.Running) == ProcessStateEnum.Running)
            {
                bEntity.ProcessState = (short)ProcessStateEnum.Completed;
                bEntity.IsProcessCompleted = 1;
                bEntity.EndedDateTime = System.DateTime.Now;
                bEntity.EndedByUserID = currentUser.UserID;
                bEntity.EndedByUserName = currentUser.UserName; 
                Update(bEntity);
            }
            else
            {
                throw new ProcessInstanceException("流程不在运行状态，不能被完成！");
            }
        }

        /// <summary>
        /// 返签流程，将流程状态置为返签，并修改流程未完成标志
        /// </summary>
        /// <param name="processInstanceID"></param>
        /// <param name="currentUser"></param>
        /// <param name="session"></param>
        internal void Reverse(long processInstanceID, 
            WfLogonUser currentUser)
        {
            var bEntity = GetById(processInstanceID);
            if (bEntity.ProcessState == (short)ProcessStateEnum.Completed)
            {
                bEntity.ProcessState = (short)ProcessStateEnum.Running;
                bEntity.IsProcessCompleted = 0;
                bEntity.LastUpdatedByUserID = currentUser.UserID;
                bEntity.LastUpdatedByUserName = currentUser.UserName;
                bEntity.LastUpdatedDateTime = System.DateTime.Now;
                
                Update(bEntity);
            }
            else
            {
                throw new ProcessInstanceException("流程不在运行状态，不能被完成！");
            }
        }

        /// <summary>
        /// 流程的取消操作
        /// </summary>
        /// <returns>是否成功</returns>
        internal bool Cancel(string appName,
            long appInstanceID, 
            Guid processGUID,
            Guid userID, 
            string userName)
        {
            var isCanceled = false;
            var entity = GetProcessInstanceLatest(appName, appInstanceID, processGUID);

            if (entity == null || entity.ProcessState != (short)ProcessStateEnum.Running)
            {
                throw new WorkflowException("无法取消流程，错误原因：当前没有运行中的流程实例，或者同时有多个运行中的流程实例（不合法数据）!");
            }

            try
            {
                
                entity.ProcessState = (short)ProcessStateEnum.Canceled;
                entity.RecordStatusInvalid = 1;
                entity.LastUpdatedByUserID = userID;
                entity.LastUpdatedByUserName = userName;
                entity.LastUpdatedDateTime = System.DateTime.Now;

                Update(entity);

                isCanceled = true;
            }
            catch(System.Exception e)
            {
                throw new WorkflowException(string.Format("取消流程实例失败，错误原因：{0}", e.Message));
            }

            return isCanceled;
        }

        /// <summary>
        /// 废弃单据下所有流程的信息
        /// </summary>
        /// <param name="appName"></param>
        /// <param name="appInstanceID"></param>
        /// <param name="processGUID"></param>
        /// <param name="userID"></param>
        /// <param name="userName"></param>
        /// <returns></returns>
        internal bool Discard(string appName, long appInstanceID, Guid processGUID, Guid userID, string userName)
        {
                //        string updSql = @"UPDATE WfProcessInstance
                //		                         SET [ProcessState] = 32, --废弃状态
                //			                         [RecordStatusInvalid] = 1, --设置记录为无效状态
                //			                         [LastUpdatedDateTime] = GETDATE(),
                //			                         [LastUpdatedByUserID] = @userID,
                //			                         [LastUpdatedByUserName] = @userName
                //		                        WHERE AppInstanceID = @appInstanceID
                //			                        AND ProcessGUID = @processGUID
                //			                        AND ProcessState <> 32"; 
           return    ProcessInstanceRepository.Discard(appName, appInstanceID, processGUID, userID, userName);
        }

        /// <summary>
        /// 流程终止操作
        /// </summary>
        /// <returns></returns>
        internal bool Terminate(int processInstanceID)
        {
            WfProcessInstance entity = ProcessInstanceRepository.Get<WfProcessInstance>(processInstanceID);

            if (entity.ProcessState == (int)ProcessStateEnum.Running
                || entity.ProcessState == (int)ProcessStateEnum.Ready
                || entity.ProcessState == (int)ProcessStateEnum.Suspended)
            {

                return true;
            }
            else
            {
                throw new ProcessInstanceException("流程已经结束，或者已经被取消！");
            }
        }

        /// <summary>
        /// 删除不正常的流程实例（流程在取消状态，才可以进行删除！）
        /// </summary>
        /// <param name="processInstanceID"></param>
        /// <returns></returns>
        internal bool Delete(int processInstanceID)
        {
            bool isDeleted = false;
            try
            {
                WfProcessInstance entity = ProcessInstanceRepository.Get<WfProcessInstance>(processInstanceID); 
                if (entity.ProcessState == (int)ProcessStateEnum.Canceled)
                {
                    ProcessInstanceRepository.Delete<WfProcessInstance>(processInstanceID); 
                    isDeleted = true;
                }
                else
                {
                    throw new ProcessInstanceException("流程只有先取消，才可以删除！");
                }
            }
            catch (System.Exception)
            {
               
                throw;
            } 

            return isDeleted;

        }
        #endregion

    }
}
